﻿#include "ifclient.h"
extern "C" {
#include "../ifclient/session.h"
}

Ifclient* Ifclient::create(const char *serverHost, unsigned short port, const char *username, const char *token, int encryptKey, int pingInteval) {
	Ifclient* client = new Ifclient(serverHost, port, username, token, encryptKey, pingInteval);
	return client;
}

Ifclient::Ifclient(const char *serverHost, unsigned short port, const char *username, const char *token, int encryptKey, int pingInteval) {
	thread = nullptr;
	session = if_session_new((char*)serverHost, port, (char*)username, (char*)token, encryptKey, pingInteval);
	if_session_setCallback(session, this, messageRecvCallback, eventRecvCallback, connectSuccessedCallback, connectErrorCallback, disconnectCallback);
}

Ifclient::~Ifclient() {
	if_session_delete(session);
}

// 初始化线程
/*void Ifclient::initTread() {
	if (thread == nullptr)
	{
		thread = new std::thread(functions, function_mutex, [](std::vector<std::function<void()>> f, std::mutex fm){
			fm.lock();
			for (auto func : f)
			{
				func();
			}
			f.clear();
			fm.unlock();
		});
	}
}*/

void Ifclient::addFunction(std::function<void()> func) {
	function_mutex.lock();
	functions.push_back(func);
	function_mutex.unlock();
}

void Ifclient::messageRecvCallback(void *userdata, ifmessage *message) {
	stringstream ss;
	if (!userdata) {
		return;
	}
	Ifclient *sockeio = (Ifclient*)userdata;
	ss << "{";
	ss << "funcName = " << "\"" << "j_messageRecvCallback" << "\"" << ",";
	ss << "uid = " << "[[" << sockeio->getLocalUsername() << "]]" << ",";
	if (message->from) {
		ss << "fromUid = " << "[[" << message->from->uid << "]]" << ",";
		ss << "fromResource = " << "\"" << message->from->resource << "\"" << ",";
	}
	if (message->to) {
		ss << "toUid = " << "[[" << message->to->uid << "]]" << ",";
		ss << "toResource = " << "\"" << message->to->resource << "\"" << ",";
	}
	ss << "id = " << message->id << ",";
	if (message->title) {
		ss << "title = " << "[[" << message->title << "]]" << ",";
	} else {
		ss << "title = " << "\"" << "" << "\"" << ",";
	}
	if (message->body) {
		ss << "body = " << "[[" << message->body << "]]" << ",";
	} else {
		ss << "body = " << "\"" << "" << "\"" << ",";
	}
	ss << "}";
	std::string eventName = ss.str();

	Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]
	{		
		CommonScriptData data(sockeio->mcb, eventName.c_str());
		ScriptEvent event(ScriptEventType::kCommonEvent, &data);
		ScriptEngineManager::getInstance()->getScriptEngine()->sendEvent(&event);
	});
}

void Ifclient::eventRecvCallback(void *userdata, ifevent *event) {
	stringstream ss;
	if (!userdata) {
		return;
	}
	Ifclient *sockeio = (Ifclient*)userdata;
	ss << "{";
	ss << "funcName = " << "\"" << "j_eventRecvCallback" << "\"" << ",";
	ss << "uid = " << "[[" << sockeio->getLocalUsername() << "]]" << ",";
	if (event->from) {
		ss << "fromUid = " << "[[" << event->from->uid << "]]" << ",";
		ss << "fromResource = " << "\"" << event->from->resource << "\"" << ",";
	}
	if (event->to) {
		ss << "toUid = " << "[[" << event->to->uid << "]]" << ",";
		ss << "toResource = " << "\"" << event->to->resource << "\"" << ",";
	}
	ss << "id = " << event->id << ",";
	ss << "type = " << (int)event->type << ",";
	ss << "eventType = " << (int)event->eventType << ",";
	ss << "actionCode = " << event->actionCode << ",";
	if (event->body) {
		ss << "body = " << "[[" << event->body << "]]" << ",";
	} else {
		ss << "body = " << "\"" << "" << "\"" << ",";
	}
	ss << "}";
	std::string eventName = ss.str();

	Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]
	{		
		CommonScriptData data(sockeio->ecb, eventName.c_str());
		ScriptEvent event(ScriptEventType::kCommonEvent, &data);
		ScriptEngineManager::getInstance()->getScriptEngine()->sendEvent(&event);
	});
}

void Ifclient::connectSuccessedCallback(void *userdata, char *extra) {
	stringstream ss;
	if (!userdata) {
		return;
	}
	Ifclient *sockeio = (Ifclient*)userdata;
	ss << "{";
	ss << "funcName = " << "\"" << "j_connectSuccessedCallback" << "\"" << ",";
	ss << "uid = " << "[[" << sockeio->getLocalUsername() << "]]" << ",";
	if (extra) {
		ss << "extra = " << "[[" << extra << "]]" << ",";
	} else {
		ss << "extra = " << "\"" << "" << "\"" << ",";
	}
	ss << "}";
	std::string eventName = ss.str();

	Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]
	{
		CommonScriptData data(sockeio->cscb, eventName.c_str());
		ScriptEvent event(ScriptEventType::kCommonEvent, &data);
		ScriptEngineManager::getInstance()->getScriptEngine()->sendEvent(&event);
	});
}

void Ifclient::connectErrorCallback(void *userdata, int type, char *reason) {
	stringstream ss;
	if (!userdata) {
		return;
	}
	Ifclient *sockeio = (Ifclient*)userdata;
	ss << "{";
	ss << "funcName = " << "\"" << "j_connectErrorCallback" << "\"" << ",";
	ss << "uid = " << "[[" << sockeio->getLocalUsername() << "]]" << ",";
	ss << "type = " << (int)type << ",";
	if (reason) {
		ss << "reason = " << "[[" << reason << "]]" << ",";
	} else {
		ss << "reason = " << "\"" << "" << "\"" << ",";
	}
	ss << "}";
	std::string eventName = ss.str();

	Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]
	{
		CommonScriptData data(sockeio->cfcb, eventName.c_str());
		ScriptEvent event(ScriptEventType::kCommonEvent, &data);
		ScriptEngineManager::getInstance()->getScriptEngine()->sendEvent(&event);
	});
}

void Ifclient::disconnectCallback(void *userdata, char *reason) {
	stringstream ss;
	if (!userdata) {
		return;
	}
	Ifclient *sockeio = (Ifclient*)userdata;
	ss << "{";
	ss << "funcName = " << "\"" << "j_disconnectCallback"  << "\"" << ",";
	ss << "uid = " << "[[" << sockeio->getLocalUsername() << "]]" << ",";
	if (reason) {
		ss << "reason = " << "[[" << reason << "]]" << ",";
	} else {
		ss << "reason = " << "\"" << "" << "\"" << ",";
	}
	ss << "}";
	std::string eventName = ss.str();

	Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]
	{
		CommonScriptData data(sockeio->dcb, eventName.c_str());
		ScriptEvent event(ScriptEventType::kCommonEvent, &data);
		ScriptEngineManager::getInstance()->getScriptEngine()->sendEvent(&event);
	});
}

int Ifclient::getState() {
	return if_session_getState(session);
}

void Ifclient::setCallback(int mcb, int ecb, int cscb, int cfcb, int dcb)
{
	this->mcb = mcb;
	this->ecb = ecb;
	this->cscb = cscb;
	this->cfcb = cfcb;
	this->dcb = dcb;
}

void Ifclient::connect(int timeout) {
	std::thread thr([this, timeout]{
		if_session_connect(session, timeout);
	});
	thr.detach();
}

void Ifclient::disconnect(bool immediately) {
	return if_session_disconnect(session, immediately);
}

int Ifclient::sendMessage(const char *to, const char *resource, const char *title, const char *data, int id) {	
	ifmessage *message = if_create_message((char*)title);
	message->from = if_session_getLocalUid(session);
	message->to = if_create_ulaid_x((char*)to, *resource);
	message->body = if_str_clone((char*)data);
	message->id = id;
	if_session_sendMessage(session, message);
	if_delete_packet_x(message, PACKET_TYPE_MESSAGE);
	return 0;
}

int Ifclient::sendEvent(const char *to, const char *resource, byte type, short eventType, int action, const char *body, int id) {
	ifevent *event = if_create_event(eventType, type, action);
	event->to = if_create_ulaid_x((char*)to, *resource);
	event->from = if_session_getLocalUid(session);
	event->body = if_str_clone((char*)body);
	event->id = id;
	if_session_sendEvent(session, event);
	if_delete_packet_x(event, PACKET_TYPE_EVENT);
	return 0;
}

int Ifclient::getMsDelay() {
	return if_session_getMsDelay(session);
}

int Ifclient::getDownloadCount() {
	return if_session_getDownloadCount(session);
}
int Ifclient::getUploadCount() {
	return if_session_getUploadCount(session);
}
unsigned short Ifclient::getPort() {
	return if_session_getPort(session);
}
char* Ifclient::getServerHost() {
	return if_session_getServerHost(session);
}
char* Ifclient::getServerName() {
	return if_session_getServerName(session);
}
char* Ifclient::getLocalUsername() {
	return if_session_getUsername(session);
}